﻿using log4net;
using log4net.Core;
using Microsoft.Extensions.Logging;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using Velocity4Net.Exceptions;
using Velocity4Net.Runtime;
/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
namespace Velocity4Net.Util{















/**
 * This class:ExtProperties to handle deprecated propery key names.
 * @since 2.1
 * @version $Revision: $
 * @version $Id: DeprecationAwareExtProperties.java$
 *
 * @author <a href="mailto:claude.brisson@gmail.com">Claude Brisson</a>
 * @deprecated it will disappear along with deprecated key names in 3.0.
 */
[Obsolete]
public class DeprecationAwareExtProperties:Dictionary<string, Object>
{
    /**
     * <p>Logger used to log the use of deprecated properties names.</p>
     * <p>Since at the time Velocity properties are set Velocity is not yet initialized,
     * this logger namespace can only be a child of the default logger name: <code>org.apache.velocity.deprecation</code>.</p>
     * <p>It won't honor the <code>runtime.log.instance</code> or <code>runtime.log.name</code> settings.</p>
     */
    protected static ILog logger = LogManager.GetLogger(RuntimeConstants.DEFAULT_RUNTIME_LOG_NAME + ".deprecation");

    /**
     * Emit a warning in the log for adeprecated property name
     * @param oldName old property name
     * @param newName new property name
     */
    protected void warnDeprecated(String oldName, String newName)
    {
        if (warned.Add(oldName))
        {
            logger.Warn($"configuration key '{oldName}' has been deprecated in favor of '{newName}'");
        }
    }

    /**
     * Translate if needed a deprecated key into its replacement key, and emit a warning for deprecated keys
     * @param key provided key
     * @return translated key
     */
    protected String translateKey(String key)
    {
        // check for a replacement key
        String replacement = propertiesReplacementMap[key];
        if (replacement != null)
        {
            warnDeprecated(key, replacement);
            return replacement;
        }
        // check for a resource loader property
        int i = key.IndexOf(".resource.loader.");
        if (i != -1)
        {
            replacement = "resource.loader." + key.Substring(0, i + 1) + key.Substring(i + 17);
            warnDeprecated(key, replacement);
            return replacement;
        }
        // check for a control scope property
        if (key.EndsWith(".provide.scope.control"))
        {
            replacement = RuntimeConstants.CONTEXT_SCOPE_CONTROL + "." + key.Substring(0, key.Length - 22);
            warnDeprecated(key, replacement);
            return replacement;
        }
        // looks good
        return key;
    }

    /**
     * Property getter which checks deprecated property keys
     * @param key provided key
     * @return found value under this key or under the corresponding deprecated one, if any
     */
    public Object get(String key)
    {
        return base[translateKey(key)];
    }

    /**
     * Property setter which checks deprecated property keys
     * @param key provided key
     * @param value provided value
     * @return previous found value, if any
     */
    public Object put(String key, Object value)
    {
        return base[translateKey(key)]= value;
    }

    /**
     * Property getter which checks deprecated property keys
     * @param key provided key
     * @return found value under this key or under the corresponding deprecated one, if any
     */
    public bool containsKey(String key)
    {
        return base.ContainsKey(translateKey(key));
    }

    /**
     * Set of old property names for which a warning has already been emitted
     */
    private ISet<String> warned = new HashSet<String>();

    /**
     * Property keys replacement map, from old key name to new key name
     */
    static private IDictionary<String, String> propertiesReplacementMap = new Dictionary<String, String>();

    static DeprecationAwareExtProperties()
    {
        {
            try
            {
                FieldInfo []oldFields = typeof(DeprecatedRuntimeConstants).GetFields();
                foreach(FieldInfo oldField in oldFields)
                {
                    String name = oldField.Name;
                    if (!name.StartsWith("OLD_")) throw new VelocityException("Could not initialize property keys deprecation map because DeprecatedRuntimeConstants." + name + " field isn't properly named");
                    if (oldField.FieldType != typeof(String)) continue;
                    String oldValue = (String)oldField.GetValue(null);
                    if (oldValue == null) throw new VelocityException("Could not initialize property keys deprecation map because DeprecatedRuntimeConstants." + name + " field isn't initialized");
                    name = name.Substring(4);
                    FieldInfo newField = typeof(RuntimeConstants).GetField(name);
                    String newValue = (String)newField.GetValue(null);
                    if (newValue == null) throw new VelocityException("Could not initialize property keys deprecation map because RuntimeConstants." + name + " field isn't initialized");
                    if (!newValue.Equals(oldValue))
                    {
                        propertiesReplacementMap.Add(oldValue, newValue);
                    }
                }
            }
            catch (Exception e)
            {
                throw new VelocityException("Could not initialize property keys deprecation map", e);
            }
        }
    }

}
}